package queue

type Queue[T interface{}] struct {
	//The size of the Queue.
	size int
	qu   []T
	//The start point of the Queue.
	start int
	//The end point of the Queue.
	end int
	//The length of the Queue.
	length int
}

// Size returns the size of the Queue.
func (q *Queue[T]) Size() int {
	return q.size
}

// Length returns the length of the Queue.
func (q *Queue[T]) Length() int {
	// if q.start == q.end {
	// 	fmt.Println("c1")
	// 	return 0
	// } else if q.start < q.end {
	// 	fmt.Println("c2")
	// 	return q.end - q.start
	// } else if q.start > q.end {
	// 	fmt.Println("c3")
	// 	return q.size - q.start + q.end
	// } else {
	// 	fmt.Println("wrong case")
	// 	// That's not the case
	// 	return 0
	// }
	return q.length
}

// Determine if the queue is empty.
func (q *Queue[T]) IsEmpty() bool {
	if q.Length() == 0 {
		return true
	} else {
		return false
	}
}

// Determine if the queue is full.
func (q *Queue[T]) IsFull() bool {
	if q.Length() == q.size {
		return true
	} else {
		return false
	}
}

// Move the end of the Queue backward.
func (q *Queue[T]) moveBackTheEnd() {
	if q.end == q.size-1 {
		q.end = 0
	} else {
		q.end += 1
	}
	q.length += 1
}

// Move the start of the Queue backward.
func (q *Queue[T]) moveBackTheStart() {
	if q.start == q.size-1 {
		q.start = 0
	} else {
		q.start += 1
	}
	q.length -= 1
}

// Push puts an element to the Queue.
// If the Queue is full,Push will return false.
func (q *Queue[T]) Push(v T) bool {
	if q.Length() == q.size {
		return false
	} else {
		q.qu[q.end] = v
		q.moveBackTheEnd()
		return true
	}
}

// Pop gets and deletes the first element of the Queue.
// If the Queue is empty,Pop will return the zero value of T and false.
func (q *Queue[T]) Pop() (T, bool) {
	var t T
	if q.Length() == 0 {
		return t, false
	} else {
		t = q.qu[q.start]
		q.moveBackTheStart()
		return t, true
	}
}

func (q *Queue[T]) Clear() {
	q.length = 0
	q.qu = make([]T, q.size)
}
